#include "TerminateToken.h"
#include "../Grammar/Grammar.h"
#include <string>

using namespace std;

void SkipSpace(CCodePtr pCode)
{
	char ch;
	while (pCode->PeekChar(ch))
	{
		if (ch != ' ' && ch != '\t' && ch != '\n')
		{
			break;
		}
		pCode->GetChar(ch);
	}
}

REGISTER_SKIP_SPACE_FUNCTION(SkipSpace);



CTerminateTokenPtr ScanWord(CCodePtr pCode)
{
	CTerminateTokenPtr pToken;
	char ch;
	string str;

	pCode->PeekChar(ch);
	if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') )
	{
		while (pCode->PeekChar(ch))
		{
			if ((ch >= 'a' && ch <= 'z')
				|| (ch >= 'A' && ch <= 'Z')
				|| (ch >= '0' && ch <= '9')
				|| ch == '_')
			{
				pCode->GetChar(ch);
				str.append(1,ch);
			}
			else 
			{				
				// Set the Token and break the loop
                pToken = CTokenFactory::createToken<CTerminateToken>(TOKEN_WORD);
                pToken->SetStringValue(str);
				break;
			}
		}
	}
	return pToken;
}

REGISTER_WORD_SCAN_FUNCTION(ScanWord);


CTerminateTokenPtr ScanNumber(CCodePtr pCode)
{
	CTerminateTokenPtr pToken;
	char ch;
	string str;

	pCode->PeekChar(ch);
	if (ch >= '0' && ch <= '9')
	{
		while (pCode->PeekChar(ch))
		{
			if (ch >= '0' && ch <= '9')
			{
				pCode->GetChar(ch);
				str.append(1,ch);
			}
			else 
			{				
				// Set the Token and break the loop
                pToken = CTokenFactory::createToken<CTerminateToken>(TOKEN_NUMBER);
                pToken->SetStringValue(str);
				break;
			}
		}

	}
	return pToken;
}

REGISTER_NUMBER_SCAN_FUNCTION(ScanNumber);


char escapeChar(char ch)
{
	switch (ch)
	{
	case 'a':
		return '\a';
	case 'b':
		return '\b';
	case 'f':
		return '\f';
	case 'n':
		return '\n';
	case 'r':
		return '\r'; 
	case 't':
		return '\t';
	case 'v':
		return '\v';
	case '\'':
		return '\'';
	case '"':
		return '\"';
	case '\\':
		return '\\';
	case '?':
		return '\?';
	case '0':
		return '\0';
	default:
		return '\0';
		// we may need a throw here
		break;
	}
}



CTerminateTokenPtr ScanString(CCodePtr pCode)
{
	CTerminateTokenPtr pToken;
	char ch;
	string str;

	pCode->PeekChar(ch);
	
	if ('"' != ch)
	{
		return pToken;
	}
	else
	{
		pCode->GetChar(ch);
	}

	while(pCode->PeekChar(ch))
	{
		pCode->GetChar(ch);
		if ('\\' == ch)
		{
			// we encounter an escape char here
			pCode->PeekChar(ch);
			pCode->GetChar(ch);
			ch = escapeChar(ch);

		}
		else if ('"' == ch)
		{
			// Set the Token and break the loop
			pToken = CTokenFactory::createToken<CTerminateToken>(TOKEN_STRING);
			pToken->SetStringValue(str);
			break;
		}

		str.append(1, ch);
	}



	return pToken;
}

REGISTER_STRING_SCAN_FUNCTION(ScanString);